package model

import (
	"errors"
	"fmt"
	"github.com/gogf/gf/encoding/gjson"
	"github.com/gogf/gf/frame/g"
	"regexp"
	"strings"
	"time"
)

var (
	TOKEN_REQ_STR = `{
    "auth": {
        "identity": {
            "methods": [
                "password"
            ],
            "password": {
                "user": {
                    "name": "${iamName}",
                    "password": "${iamPaasswd}",
                    "domain": {
                        "name": "${userName}"
                    }
                }
            }
        },
        "scope": {
            "domain": {
                "name": "${userName}"
            }
        }
    }
}`
	PUT_REQ_STR = "{\"records\": [\"%s\"],\"ttl\": 1}"
)

type ModelDdns struct {
	UserName   string
	IamName    string
	IamPaasswd string

	DomainHost string
	DomainName string

	GetIpUrl  string
	IamApiUrl string
	DnsApiUrl string
}

/*运行*/
func (modelDdns ModelDdns) Run() {
	defer func() {
		if r := recover(); r != nil {
			LogText(fmt.Sprintf("recover异常:%v", r))
		}
	}()
	//fmt.Println(modelDdns)
	token, err := modelDdns.GetToken()
	if err != nil || len(token) == 0 {
		LogText(fmt.Sprintf("请求token出错:%v", err))
		return
	}
	err = modelDdns.PutRecordset(token)
	if err != nil || len(token) == 0 {
		LogText(fmt.Sprintf("修改解析记录出错:%v", err))
		return
	}
	//fmt.Println(token)
}

func (modelDdns ModelDdns) GetToken() (string, error) {
	client := g.Client()
	client.CloseIdleConnections()
	tokenUrl := fmt.Sprintf("https://%s/v3/auth/tokens", modelDdns.IamApiUrl)
	tokenReq := strings.ReplaceAll(TOKEN_REQ_STR, "${userName}", modelDdns.UserName)
	tokenReq = strings.ReplaceAll(tokenReq, "${iamName}", modelDdns.IamName)
	tokenReq = strings.ReplaceAll(tokenReq, "${iamPaasswd}", modelDdns.IamPaasswd)
	//fmt.Printf("tokenUrl:%s tokenReq:%s\n", tokenUrl, tokenReq)
	response, err := client.ContentJson().Post(tokenUrl, tokenReq)
	defer response.Response.Body.Close()
	//defer response.Close()
	if err != nil {
		return "", err
	}
	return response.Header.Get("X-Subject-Token"), nil
}

func (modelDdns ModelDdns) PutRecordset(token string) error {
	/*getRecordsetsUrl*/
	getRecordsetsUrl := fmt.Sprintf("https://%s/v2/recordsets?name=%s.%s", modelDdns.DnsApiUrl, modelDdns.DomainHost, modelDdns.DomainName)
	headerMap := make(map[string]string, 0)
	headerMap["Content-Type"] = "application/json;charset=utf8"
	headerMap["X-Auth-Token"] = token
	recordsetStr := g.Client().Header(headerMap).GetContent(getRecordsetsUrl)
	loadJson, _ := gjson.LoadJson(recordsetStr)
	recordsets := loadJson.GetJsons("recordsets")
	if len(recordsets) == 0 {
		return errors.New("请求出错: recordsets获取失败，请检查是否配置[A记录]解析")
	}
	//获取已配置参数
	recordset := recordsets[0]
	id := recordset.Get("id")
	zoneId := recordset.Get("zone_id")
	records := recordset.GetArray("records")
	if len(records) == 0 {
		return errors.New("请求出错: records获取失败，请检查是否配置[IP]")
	}
	oldIpObj := records[0] //旧IP
	//获取公网IP
	newIp := getNetIp(modelDdns.GetIpUrl)
	if len(newIp) == 0 {
		return errors.New("获取公网IP出错")
	}
	if oldIpObj.(string) == newIp {
		//不用修改
		return nil
	}
	//修改解析记录
	bodyStr := fmt.Sprintf(PUT_REQ_STR, newIp)
	putUrl := fmt.Sprintf("https://%s/v2/zones/%s/recordsets/%s", modelDdns.DnsApiUrl, zoneId, id)
	g.Client().Header(headerMap).PutContent(putUrl, bodyStr)
	LogText("ip更新成功->[" + newIp + "]")
	return nil
}

/*
*
获取当前宽度IP
*/
func getNetIp(ipUrl string) string {
	for i := 0; i < 6; i++ {
		newIp := g.Client().GetContent(ipUrl)
		if len(newIp) != 0 && isIp(newIp) {
			return newIp
		} else {
			time.Sleep(5 * time.Second)
		}
	}
	return ""
}

func isIp(str string) bool {
	ipReg := `^((0|[1-9]\d?|1\d\d|2[0-4]\d|25[0-5])\.){3}(0|[1-9]\d?|1\d\d|2[0-4]\d|25[0-5])$`
	match, _ := regexp.MatchString(ipReg, str)
	return match
}
